package com.studerb.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.net.nntp.NNTP;
import org.apache.log4j.Logger;

import ar.com.ktulu.yenc.YEncDecoder;

import com.studerb.model.Header;
import com.studerb.service.interfaces.IDecodingService;
import com.studerb.service.interfaces.IService;
import com.studerb.util.Constants;

/**
 * Service used to decode common nntp binary formats including MIME, base64, UUencode, XXencode, Binhex, yEnc
 * @author studerb
 */
public class DecodingService implements IDecodingService, IService {

    /**
     * YENC UUENCODE - first blank line: YES / header: begin <mode> <file> / footer: `\r\n / First char: M XXENCODE -
     * header: begin <mode> <file> / First char: h
     */

    // match a multi-part: ^.*[\(\[](\d+)\/(\d+)[\)\]]/));
    public enum Encoding {
        TEXT, YENC, UUENCODE, XXENCODE, BASE64, MIME, BINHEX
    }

    private final Logger logger = Logger.getLogger(DecodingService.class);
    private boolean started = false;

    @Override public boolean isStarted() {
        return started;
    }

    @Override public void start() {
        if(started){
            throw new RuntimeException("DecodingService already Started");
        }
        logger.info("[**DecoderService Starting**]");
        started = true;
    }

    @Override public void stop() {
        if( !started){
            throw new RuntimeException("Decoding already Stopped");
        }
        logger.info("[**DecodingService Stopping**]");
        started = false;
    }

    @Override public File decodeArticle(Header header, byte[] encodedBytes) throws IOException {
        logger.debug("decoding " + encodedBytes.length + " bytes");
        byte[] decodedBytes = yencode(header, encodedBytes);
        logger.debug("Returning file with bytes of length: " + decodedBytes.length);
        File decodedFile = File
                        .createTempFile(String.valueOf(header.getArticleNumber()) + "_" + NNTP.DEFAULT_ENCODING, Constants.DECODED_FILE_SUFFIX);
        FileUtils.writeByteArrayToFile(decodedFile, decodedBytes);
        return decodedFile;
        // deleteOnexit
    }

    private byte[] yencode(final Header header, byte[] encodedBytes) {
        ByteArrayInputStream input = null;
        ByteArrayOutputStream output = null;
        try{
            YEncDecoder decoder = new YEncDecoder();
            decoder.debugMessages(true);
            input = new ByteArrayInputStream(encodedBytes);
            decoder.setInputStream(input);
            output = new ByteArrayOutputStream();
            decoder.setOutputStream(output);
            decoder.decode();
            if(output.size() == 0){
                throw new IOException("Yenc returned 0 bytes output without throwing exception...");
            }
            return output.toByteArray();
        }
        catch(Exception e){
            logger.debug("Decoding error: " + ExceptionUtils.getRootCauseMessage(e));
            return encodedBytes;
        }
        finally{
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }
}
